import json
from decimal import Decimal

from django.db import transaction
from django.utils import timezone

from django import http
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render
from django.views import View
from django_redis import get_redis_connection

from apps.areas.models import Address
from apps.goods.models import SKU
from apps.orders.models import OrderInfo, OrderGoods
from utils.response_code import RETCODE
from utils.views import LoginRequiredJSONMixin


class OrderSettlementView(LoginRequiredMixin, View):
    """结算订单"""

    def get(self, request):
        """提供订单结算页面"""
        # 获取登录用户
        user = request.user
        # 查询地址信息
        try:
            address = Address.objects.filter(user_id=request.user.id).filter(is_deleted=0)
            print(address)

        except Address.DoesNotExist:
            # 如果地址为空，渲染模板时会判断，并跳转到地址编辑页面
            address = None

        # 从Redis购物车中查询出被勾选的商品信息
        redis_conn = get_redis_connection('carts')
        redis_cart = redis_conn.hgetall('carts_%s' % user.id)
        cart_selected = redis_conn.smembers('selected_%s' % user.id)
        cart = {}
        for sku_id in cart_selected:
            cart[int(sku_id)] = int(redis_cart[sku_id])

        # 准备初始值
        total_count = 0
        total_amount = Decimal(0.00)
        # 查询商品信息
        skus = SKU.objects.filter(id__in=cart.keys())
        for sku in skus:
            sku.count = cart[sku.id]
            sku.amount = sku.count * sku.price
            # 计算总数量和总金额
            total_count += sku.count
            total_amount += sku.count * sku.price
        # 补充运费
        freight = Decimal('10.00')

        # 渲染界面
        context = {
            'addresses': address,
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': freight,
            'payment_amount': total_amount + freight
        }

        return render(request, 'Orders.html', context)


class OrderCommitView(LoginRequiredJSONMixin, View):
    """订单提交"""

    def post(self, request):
        """保存订单信息和订单商品信息"""
        # 获取当前要保存的订单数据
        # json_dict = json.loads(request.body.decode())
        address = Address.objects.filter(user_id=request.user.id).filter(is_deleted=0)
        for i in address:
            address_id = i.id
            print(address_id)
            pay_method = 2
            # data_labelauty = request.POST.get('data-labelauty')
            print(address_id)
            print(pay_method)
            # print(data_labelauty)
            # 校验参数
            if not all([address_id, pay_method]):
                return http.HttpResponseBadRequest('缺少必传参数')
            # 判断address_id是否合法
            try:
                address = Address.objects.get(id=address_id)
                # 判断这个收货地址是否属于当前登录用户
                if address.user != request.user:
                    # 如果不属于当前用户，那么返回错误信息信息
                    return http.HttpResponseBadRequest('参数address_id错误')
            except Exception:
                return http.HttpResponseBadRequest('参数address_id错误')
            # 判断pay_method是否合法
            if int(pay_method) not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
                return http.HttpResponseBadRequest('参数pay_method错误')

            # 获取登录用户
            user = request.user
            # 生成订单编号：年月日时分秒+用户编号
            order_id = timezone.now().strftime('%Y%m%d%H%M%S') + '%09d' % user.id

            # ------- 修改了代码-------
            # 显式的开启一个事务
            with transaction.atomic():
                # 创建事务保存点
                save_id = transaction.savepoint()
                # ------- 修改了代码-------
                try:

                    # 保存订单基本信息 OrderInfo（一）
                    order = OrderInfo.objects.create(
                        order_id=order_id,
                        user=user,
                        address=address,
                        total_count=0,
                        total_amount=Decimal('0'),
                        freight=Decimal('10.00'),
                        pay_method=pay_method,
                        status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM[
                            'ALIPAY'] else
                        OrderInfo.ORDER_STATUS_ENUM['UNSEND']
                    )

                    # 从redis读取购物车中被勾选的商品信息
                    redis_conn = get_redis_connection('carts')
                    redis_cart = redis_conn.hgetall('carts_%s' % user.id)
                    selected = redis_conn.smembers('selected_%s' % user.id)
                    carts = {}
                    for sku_id in selected:
                        carts[int(sku_id)] = int(redis_cart[sku_id])
                    sku_ids = carts.keys()

                    # 遍历购物车中被勾选的商品信息
                    for sku_id in sku_ids:
                        # 查询SKU信息
                        sku = SKU.objects.get(id=sku_id)
                        # 判断SKU库存
                        sku_count = carts[sku.id]
                        if sku_count > sku.stock:
                            # ------- 修改了代码-------
                            # 出错就回滚
                            transaction.savepoint_rollback(save_id)
                            return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})

                        # 注意下面的方式，并没有开启事务，所以在后续版本中需要进行更新
                        # SKU减少库存，增加销量
                        sku.stock -= sku_count
                        sku.sales += sku_count
                        sku.save()

                        # 保存订单商品信息 OrderGoods（多）
                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=sku_count,
                            price=sku.price,
                        )

                        # 保存商品订单中总价和总数量
                        order.total_count += sku_count
                        order.total_amount += sku_count * sku.price

                    # 添加邮费和保存订单信息
                    order.total_amount += order.freight
                    order.save()
                except Exception as e:  # ------- 修改了代码-------
                    transaction.savepoint_rollback(save_id)
                    return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '下单失败'})

                # ------- 修改了代码-------
                # 提交订单成功，显式的提交一次事务
                transaction.savepoint_commit(save_id)

            # 清除购物车中已结算的商品
            pl = redis_conn.pipeline()
            pl.hdel('carts_%s' % user.id, *selected)
            pl.srem('selected_%s' % user.id, *selected)
            pl.execute()
            pay_method = request.GET.get('pay_method')

            context = {
                'order_id': order.order_id,
                'payment_amount': order.total_amount,
                'pay_method': pay_method
            }
            return render(request, 'order_success.html', context)
            # 响应提交订单结果
